/*
 * The RavenX Library
 * Copyright (c) 2008 by Solidus
 * 
 * Permission to use, copy, modify, distribute and sell this software
 * and its documentation for any purpose is hereby granted without fee,
 * provided that the above copyright notice appear in all copies and
 * that both that copyright notice and this permission notice appear
 * in supporting documentation.It is provided "as is" without express 
 * or implied warranty.
 *
 */
#include "rx_string.h"
#include "rx_debug.h"
#include "rx_mem.h"
#include "rx_misc.h"
#include <string.h>
RX_SPACE_BEG


#define __str_def_alloc (*(rx_mem_default_alloctor()))


static RX_INLINE void* __str_alloc(size_t size)
{
		void *ptr = __str_def_alloc.alloc_f(size, __str_def_alloc.ctx);
		RX_FATAL_ERROR(ptr != NULL);
		return ptr;
}


static RX_INLINE void* __str_realloc(void *ptr, size_t size)
{
		ptr = __str_def_alloc.realloc_f(ptr, size, __str_def_alloc.ctx);
		RX_FATAL_ERROR(ptr != NULL);
		return ptr;
}

static RX_INLINE void __str_free(void *ptr)
{
		if(ptr != NULL)__str_def_alloc.dealloc_f(ptr,   __str_def_alloc.ctx);
		
}


#undef __str_def_alloc






/******************************************************************************************************************************************/


typedef struct __rx_wstr_tag
{
		rx_wchar		*str;
		size_t			str_len;
		size_t			alloc_len;
}rx_wstr_t;

void			rx_wstr_trimleft(rx_wstr_t *self, const rx_wchar *target)
{
		rx_wchar *p = NULL;
		RX_ASSERT(self != NULL);
		if(target == NULL || rx_wstr_size(self) == 0)return;

		p = self->str;

		while(*p != 0)
		{
				const rx_wchar *t = target;
				while(*t != 0 && *p != *t) t++;
				
				if(*t == 0)break;
				p++;
		}

		if(p != self->str)
		{
				self->str_len = wcslen(p);
				rx_wmemmove(self->str, p, self->str_len + 1);
		}
}

void			rx_wstr_trimright(rx_wstr_t *self, const rx_wchar *target)
{
		rx_wchar *p = NULL, *plast = NULL;
		RX_ASSERT(self != NULL);
		if(target == NULL || rx_wstr_size(self) == 0)return;
		
		p = self->str;

		while(*p != 0)
		{
				const rx_wchar *t = target;
				while(*t != 0 && *p != *t)t++;

				if(*t == 0)
				{
						plast = NULL;
				}else if(plast == NULL)
				{
						plast = p;
				}
				++p;
		}
		
		if(plast != NULL)
		{
				self->str_len = plast - self->str;
				self->str[self->str_len] = 0;
		}
}

void	rx_wstr_trim(rx_wstr_t *self, const rx_wchar *target)
{
		rx_wstr_trimleft(self, target);
		rx_wstr_trimright(self, target);
}


rx_wstr_t*	rx_wstr_dup(const rx_wstr_t *self)
{
		rx_wstr_t* res;
		RX_ASSERT(self != NULL);
		res = rx_wstr_create();
		rx_wstr_append(res, rx_wstr_cstr(self));
		return res;
}

void	rx_wstr_copy(rx_wstr_t *dest, const rx_wstr_t *self)
{
		RX_ASSERT(dest != NULL && self != NULL);
		rx_wstr_clear(dest);
		rx_wstr_append(dest, rx_wstr_cstr(self));
}

rx_wstr_t*		rx_wstr_substr(const rx_wstr_t *self, size_t first, size_t last)
{
		rx_wstr_t *res;
		
		RX_ASSERT(self != NULL);
		if(last > self->str_len) last = self->str_len;
		RX_ASSERT(first <= last);

		res = rx_wstr_create();

		if(first == last)return res;

		rx_wstr_reserve(res, last - first);
		
		while(first < last) res->str[res->str_len++] = self->str[first++];
		
		res->str[res->str_len] = 0;
		
		return res;
}

void			rx_wstr_clear(rx_wstr_t *self)
{
		RX_ASSERT(self != NULL);
		if(self->str_len > 0) {self->str_len = 0; self->str[self->str_len] = 0;}

}

void	rx_wstr_insert_value(rx_wstr_t *self, size_t pos, rx_wchar value, size_t n)
{
		size_t need_cap, old_cap;
		RX_ASSERT(self != NULL);
		if(n < 1)return;

		need_cap = rx_wstr_size(self) + n + 1;
		old_cap = rx_wstr_capacity(self);
		if(need_cap <= old_cap)
		{
				size_t s = rx_wstr_size(self), d = rx_wstr_size(self) + n;
				while(pos < s) { self->str[--d] = self->str[--s];}
				for(s = 0; s < n; ++s) self->str[pos + s] = value;
				
		}else
		{		
				rx_wchar *new_str;
				size_t i;
				need_cap = rx_max(old_cap * 2, need_cap);
				new_str = (rx_wchar*)__str_alloc(need_cap * sizeof(rx_wchar));
				
				if(pos > 0)rx_wmemcpy(new_str, self->str, pos);
				for(i = 0; i < n; ++i) new_str[pos + i] = value;
				rx_wmemcpy(new_str + pos + n, self->str + pos, self->str_len - pos);
				__str_free(self->str);
				self->str = new_str;
				self->alloc_len = need_cap;
		}

		self->str_len += n;
		self->str[self->str_len] = 0;

}


void	rx_wstr_insert(rx_wstr_t *self, size_t pos, const rx_wchar *str)
{
		size_t need_cap, old_cap, n;
		RX_ASSERT(self != NULL && str != NULL);
		
		n = wcslen(str);
		if(n < 1) return;

		need_cap = rx_wstr_size(self) + n + 1;
		old_cap = rx_wstr_capacity(self);
		if(need_cap <= old_cap)
		{
				size_t s = rx_wstr_size(self), d = rx_wstr_size(self) + n;
				while(pos < s) { self->str[--d] = self->str[--s];}
				for(s = 0; s < n; ++s) self->str[pos + s] = *(str + s);
				
		}else
		{		
				rx_wchar *new_str;
				size_t i;
				need_cap = rx_max(old_cap * 2, need_cap);
				new_str = (rx_wchar*)__str_alloc(need_cap * sizeof(rx_wchar));
				
				if(pos > 0)rx_wmemcpy(new_str, self->str, pos);
				for(i = 0; i < n; ++i) new_str[pos + i] = *(str + i);
				rx_wmemcpy(new_str + pos + n, self->str + pos, self->str_len - pos);
				__str_free(self->str);
				self->str = new_str;
				self->alloc_len = need_cap;
		}

		self->str_len += n;
		self->str[self->str_len] = 0;
}


void	rx_wstr_append(rx_wstr_t *self, const rx_wchar *str)
{
		rx_wstr_insert(self, self->str_len, str);
}



rx_wstr_t*		rx_wstr_create()
{
		/*rx_wstr_t *res = (rx_wstr_t*)__str_alloc(sizeof(rx_wstr_t));
		res->alloc_len = res->str_len = 0;
		res->str = NULL;
		return res;*/

		return rx_unistr_to_wstr(rx_unistr_create_wstr(RX_WIDE_STR("")));
}


void	rx_wstr_destroy(rx_wstr_t *self)
{
		/*if(self != NULL)
		{
				__str_free(self->str);
				__str_free(self);
		}*/

		rx_unistr_destroy(rx_wstr_to_unistr(self));
}



size_t			rx_wstr_size(const rx_wstr_t *self)
{
		RX_ASSERT(self != NULL);
		return self->str_len;
}

size_t			rx_wstr_capacity(const rx_wstr_t *self)
{
		RX_ASSERT(self != NULL);
		return self->alloc_len;

}

void			rx_wstr_reserve(rx_wstr_t *self, size_t num)
{
		RX_ASSERT(self != NULL);
		num += 1;

		if(self->alloc_len < num)
		{
				self->alloc_len = num;
				self->str = (rx_wchar*)__str_realloc(self->str, self->alloc_len * sizeof(rx_wchar));
		}

}



void			rx_wstr_erase_pos(rx_wstr_t *self, size_t pos)
{
		size_t i;
		RX_ASSERT(self != NULL && pos < self->str_len);

		if(pos == self->str_len - 1) { self->str[--self->str_len] = 0;return;}
		
		for(i = pos; i < self->str_len - 1; ++i) self->str[i] = self->str[i + 1];

		self->str[--self->str_len] = 0;
}


void			rx_wstr_erase_range(rx_wstr_t *self, size_t first, size_t last)
{
		size_t erase_n , i;
		RX_ASSERT(self != NULL);
		if(last > rx_wstr_size(self)) last = rx_wstr_size(self);
		RX_ASSERT( first < last);

		erase_n = last - first;

		for(i = 0; last + i < self->str_len; i++)self->str[first + i] = self->str[last + i];

		self->str_len -= erase_n;
		self->str[self->str_len] = 0;
}

void			rx_wstr_erase_value(rx_wstr_t *self, size_t start_pos, rx_wchar value)
{
		size_t i;
		RX_ASSERT(self != NULL && start_pos < self->str_len);

		for(i = start_pos; i < self->str_len; ++i)
		{
				if(self->str[i] == value)break;
		}
		
		if( i < self->str_len)
		{
				rx_wchar *d,*s = self->str + i;

				for(d = s; i < self->str_len; ++i)
				{
						if(*d == *s)
						{
								s++;
						}
						else
						{
								*d++ = *s++;
						}
				}
		}
}



rx_wchar*		rx_wstr_begin(rx_wstr_t *self)
{
		RX_ASSERT(self != NULL);

		if(self->str_len == 0)
		{
				return NULL;
		}else
		{
				return self->str;
		}
}

rx_wchar*		rx_wstr_end(rx_wstr_t *self)
{
		RX_ASSERT(self != NULL);

		if(self->str_len == 0)return NULL;

		return self->str + self->str_len;


}

rx_wchar*		rx_wstr_at(rx_wstr_t *self, size_t idx)
{
		RX_ASSERT(self != NULL && idx < self->str_len);

		return self->str + idx;

}

const rx_wchar* rx_wstr_cstr(const rx_wstr_t *self)
{
		RX_ASSERT(self != NULL);

		return (self->str_len > 0 ?self->str : RX_WIDE_STR(""));

}



rx_bool		rx_wstr_format(rx_wstr_t *self, const rx_wchar *fmt,...)
{
		int n;
		va_list args_ptr = NULL;
		RX_ASSERT(self != NULL && fmt != NULL);
		
		
		va_start(args_ptr, fmt);
		
		n = rx_vscwprintf(fmt, args_ptr);

		va_end(args_ptr);
		
		
		if(n < 0)return rx_false;
		if(n == 0) { rx_wstr_clear(self); return rx_true;}
		
		
		

		rx_wstr_reserve(self, n + 1);
		
		self->str_len = n;
		self->str[0] = 0;
		
		va_start(args_ptr, fmt);
		rx_vswprintf(self->str, n + 1, fmt, args_ptr);
		va_end(args_ptr);
		
		self->str_len = wcslen(self->str);

		return rx_true;
}

rx_bool		rx_wstr_append_format(rx_wstr_t *self, const rx_wchar *fmt,...)
{
		int n;
		va_list args_ptr = NULL;
		rx_wchar *buf;
		RX_ASSERT(self != NULL && fmt != NULL);
		
		
		va_start(args_ptr, fmt);
		
		n = rx_vscwprintf(fmt, args_ptr);

		va_end(args_ptr);
		
		
		if(n < 0)return rx_false;
		if(n == 0) { return rx_true;}



		buf = (rx_wchar*)__str_alloc((n + 1) * sizeof(rx_wchar));
		
		va_start(args_ptr, fmt);
		rx_vswprintf(buf, n + 1, fmt, args_ptr);
		va_end(args_ptr);
		
		rx_wstr_append(self, buf);
		__str_free(buf);

		return rx_true;
}





int	rx_wstr_search_pos(const rx_wstr_t *self, size_t pos, const rx_wchar *key)
{
		const rx_wchar *res;
		RX_ASSERT(self != NULL && pos < self->str_len && key != NULL);
		
		res = wcsstr(rx_wstr_cstr(self) + pos, key);

		if(res == NULL)return -1;
		return (int)(res - self->str);
}

int	rx_wstr_search(const rx_wstr_t *self, const rx_wchar *key)
{
		return rx_wstr_search_pos(self, 0, key);
}

int	rx_wstr_cmp(const rx_wstr_t *left, const rx_wstr_t *right)
{
		return wcscmp(rx_wstr_cstr(left), rx_wstr_cstr(right));
}


rx_uint_n rx_wstr_hash(const rx_wstr_t *self)
{
		return rx_hash_byte((const rx_byte*)self->str, (self->str_len + 1) * sizeof(rx_wchar));
}




/************************************************************************************/


typedef struct __rx_str_tag
{
		rx_char		*str;
		size_t		str_len;
		size_t		alloc_len;
}rx_str_t;


rx_str_t*	rx_str_dup(const rx_str_t *self)
{
		rx_str_t* res;
		RX_ASSERT(self != NULL);
		res = rx_str_create();
		rx_str_append(res, rx_str_cstr(self));
		return res;
}

void	rx_str_copy(rx_str_t *dest, const rx_str_t *self)
{
		RX_ASSERT(dest != NULL && self != NULL);
		rx_str_clear(dest);
		rx_str_append(dest, rx_str_cstr(self));
}


rx_str_t*		rx_str_substr(const rx_str_t *self, size_t first, size_t last)
{
		rx_str_t *res;
		
		RX_ASSERT(self != NULL);
		if(last > self->str_len) last = self->str_len;
		RX_ASSERT(first <= last);

		res = rx_str_create();

		if(first == last)return res;

		rx_str_reserve(res, last - first);
		
		while(first < last) res->str[res->str_len++] = self->str[first++];
		
		res->str[res->str_len] = 0;
		
		return res;
}

void	rx_str_clear(rx_str_t *self)
{
		RX_ASSERT(self != NULL);
		if(self->str_len > 0) {self->str_len = 0; self->str[self->str_len] = 0;}

}

void	rx_str_insert_value(rx_str_t *self, size_t pos, rx_char value, size_t n)
{
		size_t need_cap, old_cap;
		RX_ASSERT(self != NULL);
		if(n < 1)return;

		need_cap = rx_str_size(self) + n + 1;
		old_cap = rx_str_capacity(self);
		if(need_cap <= old_cap)
		{
				size_t s = rx_str_size(self), d = rx_str_size(self) + n;
				while(pos < s) { self->str[--d] = self->str[--s];}
				for(s = 0; s < n; ++s) self->str[pos + s] = value;
				
		}else
		{		
				rx_char *new_str;
				size_t i;
				need_cap = rx_max(old_cap * 2, need_cap);
				new_str = (rx_char*)__str_alloc(need_cap * sizeof(rx_char));
				
				if(pos > 0)rx_memcpy(new_str, self->str, pos);
				for(i = 0; i < n; ++i) new_str[pos + i] = value;
				rx_memcpy(new_str + pos + n, self->str + pos, self->str_len - pos);
				__str_free(self->str );
				self->str = new_str;
				self->alloc_len = need_cap;
		}

		self->str_len += n;
		self->str[self->str_len] = 0;

}


void	rx_str_insert(rx_str_t *self, size_t pos, const rx_char *str)
{
		size_t need_cap, old_cap, n;
		RX_ASSERT(self != NULL && str != NULL);
		
		n = strlen(str);
		if(n < 1) return;

		need_cap = rx_str_size(self) + n + 1;
		old_cap = rx_str_capacity(self);
		if(need_cap <= old_cap)
		{
				size_t s = rx_str_size(self), d = rx_str_size(self) + n;
				while(pos < s) { self->str[--d] = self->str[--s];}
				for(s = 0; s < n; ++s) self->str[pos + s] = *(str + s);
				
		}else
		{		
				rx_char *new_str;
				size_t i;
				need_cap = rx_max(old_cap * 2, need_cap);
				new_str = (rx_char*)__str_alloc(need_cap * sizeof(rx_char));
				
				if(pos > 0)rx_memcpy(new_str, self->str, pos);
				for(i = 0; i < n; ++i) new_str[pos + i] = *(str + i);
				rx_memcpy(new_str + pos + n, self->str + pos, self->str_len - pos);
				__str_free(self->str );
				self->str = new_str;
				self->alloc_len = need_cap;
		}

		self->str_len += n;
		self->str[self->str_len] = 0;
}


void	rx_str_append(rx_str_t *self, const rx_char *str)
{
		rx_str_insert(self, self->str_len, str);
}



rx_str_t*		rx_str_create()
{
		/*
		rx_str_t *res = (rx_str_t*)__str_alloc(sizeof(rx_str_t));
		res->alloc_len = res->str_len = 0;
		res->str = NULL;
		return res;
		*/
		return rx_unistr_to_str(rx_unistr_create_str(""));
}


void	rx_str_destroy(rx_str_t *self)
{
		/*if(self != NULL)
		{
				__str_free(self->str );
				__str_free(self);
		}*/

		rx_unistr_destroy(rx_str_to_unistr(self));
}



size_t			rx_str_size(const rx_str_t *self)
{
		RX_ASSERT(self != NULL);
		return self->str_len;
}

size_t			rx_str_capacity(const rx_str_t *self)
{
		RX_ASSERT(self != NULL);
		return self->alloc_len;
}

void			rx_str_reserve(rx_str_t *self, size_t num)
{
		RX_ASSERT(self != NULL);
		num += 1;

		if(self->alloc_len < num)
		{
				self->alloc_len = num;
				self->str = (rx_char*)__str_realloc(self->str, self->alloc_len * sizeof(rx_char));
		}

}



void			rx_str_erase_pos(rx_str_t *self, size_t pos)
{
		size_t i;
		RX_ASSERT(self != NULL && pos < self->str_len);

		if(pos == self->str_len - 1) { self->str[--self->str_len] = 0;return;}
		
		for(i = pos; i < self->str_len - 1; ++i) self->str[i] = self->str[i + 1];

		self->str[--self->str_len] = 0;
}


void			rx_str_erase_range(rx_str_t *self, size_t first, size_t last)
{
		size_t erase_n , i;
		RX_ASSERT(self != NULL);
		if(last > rx_str_size(self)) last = rx_str_size(self);
		RX_ASSERT( first < last);

		erase_n = last - first;

		for(i = 0; last + i < self->str_len; i++)self->str[first + i] = self->str[last + i];

		self->str_len -= erase_n;
		self->str[self->str_len] = 0;
}

void			rx_str_erase_value(rx_str_t *self, size_t start_pos, rx_char value)
{
		size_t i;
		RX_ASSERT(self != NULL && start_pos < self->str_len);

		for(i = start_pos; i < self->str_len; ++i)
		{
				if(self->str[i] == value)break;
		}
		
		if( i < self->str_len)
		{
				rx_char *d,*s = self->str + i;

				for(d = s; i < self->str_len; ++i)
				{
						if(*d == *s)
						{
								s++;
						}
						else
						{
								*d++ = *s++;
						}
				}
		}
}



rx_char*		rx_str_begin(rx_str_t *self)
{
		RX_ASSERT(self != NULL);

		if(self->str_len == 0)
		{
				return NULL;
		}else
		{
				return self->str;
		}
}

rx_char*		rx_str_end(rx_str_t *self)
{
		RX_ASSERT(self != NULL);

		if(self->str_len == 0)return NULL;

		return self->str + self->str_len;


}

rx_char*		rx_str_at(rx_str_t *self, size_t idx)
{
		RX_ASSERT(self != NULL && idx < self->str_len);

		return self->str + idx;

}

const rx_char* rx_str_cstr(const rx_str_t *self)
{
		RX_ASSERT(self != NULL);

		return (self->str_len > 0 ?self->str : "");

}



rx_bool		rx_str_format(rx_str_t *self, const rx_char *fmt,...)
{
		int n;
		va_list args_ptr = NULL;
		RX_ASSERT(self != NULL && fmt != NULL);
		
		
		va_start(args_ptr, fmt);
		
		n = rx_vscprintf(fmt, args_ptr);

		va_end(args_ptr);
		
		
		if(n < 0)return rx_false;
		if(n == 0) { rx_str_clear(self); return rx_true;}
		
		
		

		rx_str_reserve(self, n + 1);
		
		self->str_len = n;
		self->str[0] = 0;
		
		va_start(args_ptr, fmt);
		rx_vsprintf(self->str, n + 1, fmt, args_ptr);
		va_end(args_ptr);

		self->str_len = strlen(self->str);

		return rx_true;

}



rx_bool		rx_str_append_format(rx_str_t *self, const rx_char *fmt,...)
{
		int n;
		va_list args_ptr = NULL;
		rx_char *buf;
		RX_ASSERT(self != NULL && fmt != NULL);
		
		
		va_start(args_ptr, fmt);
		
		n = rx_vscprintf(fmt, args_ptr);

		va_end(args_ptr);
		
		
		if(n < 0)return rx_false;
		if(n == 0) { return rx_true;}

		buf = (rx_char*)__str_alloc((n + 1) * sizeof(rx_char));
		
		va_start(args_ptr, fmt);
		rx_vsprintf(buf, n + 1, fmt, args_ptr);
		va_end(args_ptr);
		
		rx_str_append(self, buf);
		__str_free(buf);

		return rx_true;
}




int	rx_str_search_pos(const rx_str_t *self, size_t pos, const rx_char *key)
{
		const rx_char *res;
		RX_ASSERT(self != NULL && pos < self->str_len && key != NULL);
		
		res = strstr(rx_str_cstr(self) + pos, key);

		if(res == NULL)return -1;
		return (int)(res - self->str);
}

int	rx_str_search(const rx_str_t *self, const rx_char *key)
{
		return rx_str_search_pos(self, 0, key);
}

int	rx_str_cmp(const rx_str_t *left, const rx_str_t *right)
{
		return strcmp(rx_str_cstr(left), rx_str_cstr(right));
}



rx_uint_n rx_str_hash(const rx_str_t *self)
{
		return rx_hash_byte((const rx_byte*)self->str, (self->str_len + 1) * sizeof(rx_char));
}






/************************************uni_str*****************************************/

typedef enum {MBCS_STR, WCS_STR} __str_type;

typedef struct __rx_unistr_tag
{
		union {
				rx_wstr_t		wstr;
				rx_str_t		str;
		};

		__str_type				type;
}rx_unistr_t;

rx_unistr_t* rx_unistr_create()
{
		rx_unistr_t*	res;
		res = (rx_unistr_t*)__str_alloc(sizeof(rx_unistr_t));
		rx_memset(res, 0, sizeof(rx_unistr_t));
		res->type = WCS_STR;
		return res;
}

void rx_unistr_destroy(rx_unistr_t *pstr)
{
		if(pstr != NULL)
		{
				if(pstr->type == WCS_STR) 
				{
						if(pstr->wstr.str != NULL)
								__str_free(pstr->wstr.str);
						
				}else
				{
						if(pstr->str.str != NULL)
								__str_free(pstr->str.str);
				}

				__str_free(pstr );
		}
}

rx_unistr_t* rx_unistr_create_wstr(const rx_wchar *str)
{
		rx_unistr_t* res = rx_unistr_create();
		rx_wstr_append(&res->wstr, str);
		res->type = WCS_STR;
		return res;
}

rx_unistr_t* rx_unistr_create_str(const rx_char *str)
{
		rx_unistr_t* res = rx_unistr_create();
		rx_str_append(&res->str, str);
		res->type = MBCS_STR;
		return res;
}


rx_wstr_t*	rx_unistr_to_wstr(rx_unistr_t *pstr)
{
		rx_wstr_t *tmp;
		int len;
		RX_ASSERT(pstr != NULL);

		if(pstr->type == MBCS_STR)
		{
				tmp = rx_wstr_create();
				
				if(rx_str_size(&pstr->str) > 0)
				{
						len = __cstr_to_wstr(rx_str_cstr(&pstr->str), NULL);

						if(len > 0)
						{
								rx_wstr_reserve(tmp, len);
								len = __cstr_to_wstr(rx_str_cstr(&pstr->str), tmp->str);
								if(len > 0)tmp->str[len - 1] = 0;
								tmp->str_len = len - 1;
						}

						__str_free(pstr->str.str );
						rx_memset(pstr, 0, sizeof(rx_unistr_t));
						rx_wstr_copy(&pstr->wstr, tmp);
						rx_wstr_destroy(tmp);
				}
				
				pstr->type = WCS_STR;		
		}
		
		
		return (rx_wstr_t*)pstr;
}

rx_str_t*	rx_unistr_to_utf8(rx_unistr_t *pstr)
{
		rx_str_t *tmp;
		int len;
		RX_ASSERT(pstr != NULL);

		if(pstr->type == WCS_STR)
		{
				tmp = rx_str_create();
				
				if(rx_wstr_size(&pstr->wstr) > 0)
				{
						len = __wstr_to_cstr_utf8(rx_wstr_cstr(&pstr->wstr), NULL);

						if(len > 0)
						{
								rx_str_reserve(tmp, len);
								len = __wstr_to_cstr_utf8(rx_wstr_cstr(&pstr->wstr), tmp->str);
								if(len > 0)tmp->str[len - 1] = 0;
								tmp->str_len = len - 1;
						}

						__str_free(pstr->wstr.str );
						rx_memset(pstr, 0, sizeof(rx_unistr_t));
						rx_str_copy(&pstr->str, tmp);
						rx_str_destroy(tmp);
				}
				
				pstr->type = MBCS_STR;		
		}
		
		return (rx_str_t*)pstr;
}

rx_str_t*	rx_unistr_to_str(rx_unistr_t *pstr)
{
		rx_str_t *tmp;
		int len;
		RX_ASSERT(pstr != NULL);

		if(pstr->type == WCS_STR)
		{
				tmp = rx_str_create();
				
				if(rx_wstr_size(&pstr->wstr) > 0)
				{
						len = __wstr_to_cstr(rx_wstr_cstr(&pstr->wstr), NULL);

						if(len > 0)
						{
								rx_str_reserve(tmp, len);
								len = __wstr_to_cstr(rx_wstr_cstr(&pstr->wstr), tmp->str);
								if(len > 0)tmp->str[len - 1] = 0;
								tmp->str_len = len - 1;
						}

						__str_free(pstr->wstr.str );
						rx_memset(pstr, 0, sizeof(rx_unistr_t));
						rx_str_copy(&pstr->str, tmp);
						rx_str_destroy(tmp);
				}
				
				pstr->type = MBCS_STR;		
		}
		
		
		return (rx_str_t*)pstr;
}

rx_unistr_t* rx_wstr_to_unistr(rx_wstr_t *pstr)
{
		RX_ASSERT(pstr != NULL);

		return (rx_unistr_t*)pstr;

}


rx_unistr_t* rx_str_to_unistr(rx_str_t	*pstr)
{
		RX_ASSERT(pstr != NULL);
		return (rx_unistr_t*)pstr;
}





void			rx_str_trimleft(rx_str_t *self, const rx_char *target)
{
		rx_char *p = NULL;
		RX_ASSERT(self != NULL);
		if(target == NULL || rx_str_size(self) == 0)return;

		p = self->str;

		while(*p != 0)
		{
				const rx_char *t = target;
				while(*t != 0 && *p != *t) t++;
				
				if(*t == 0)break;
				p++;
		}

		if(p != self->str)
		{
				self->str_len = strlen(p);
				rx_memmove(self->str, p, self->str_len + 1);
		}
}


void			rx_str_trimright(rx_str_t *self, const rx_char *target)
{
		rx_char *p = NULL, *plast = NULL;
		RX_ASSERT(self != NULL);
		if(target == NULL || rx_str_size(self) == 0)return;
		
		p = self->str;

		while(*p != 0)
		{
				const rx_char *t = target;
				while(*t != 0 && *p != *t)t++;

				if(*t == 0)
				{
						plast = NULL;
				}else if(plast == NULL)
				{
						plast = p;
				}
				++p;
		}
		
		if(plast != NULL)
		{
				self->str_len = plast - self->str;
				self->str[self->str_len] = 0;
		}
}

void	rx_str_trim(rx_str_t *self, const rx_char *target)
{
		rx_str_trimleft(self, target);
		rx_str_trimright(self, target);
}

rx_unistr_t* rx_unistr_dup(const rx_unistr_t *self)
{
		rx_unistr_t*res;
		RX_ASSERT(self != NULL);

		res = (rx_unistr_t*)__str_alloc(sizeof(rx_unistr_t));
		
		rx_memset(res, 0, sizeof(rx_unistr_t));

		if(self->type == MBCS_STR)
		{
				res->type = MBCS_STR;
				rx_str_copy(&res->str, &self->str);
		}else
		{
				res->type = WCS_STR;
				rx_wstr_copy(&res->wstr, &self->wstr);
		}
		return res;
}



void rx_unistr_copy(rx_unistr_t *dest, const rx_unistr_t *self)
{
		RX_ASSERT(self != NULL && dest != NULL);

		if(self->type == MBCS_STR)
		{
				if(dest->type != MBCS_STR)
				{
						__str_free(dest->wstr.str );
						dest->str.str = NULL;
						dest->str.alloc_len = 0;
						dest->str.str_len = 0;
						dest->type = MBCS_STR;
				}
				
				rx_str_copy(&dest->str, &self->str);
		}else
		{
				if(dest->type != WCS_STR)
				{
						__str_free(dest->str.str );
						dest->wstr.str = NULL;
						dest->wstr.alloc_len = 0;
						dest->wstr.str_len = 0;
						dest->type = WCS_STR;
				}
				rx_wstr_copy(&dest->wstr, &self->wstr);
		}

}


const rx_char* rx_unistr_cstr(const rx_unistr_t *self)
{
		return (rx_str_cstr(rx_unistr_to_str((rx_unistr_t*)self)));

}

const rx_wchar* rx_unistr_wcstr(const rx_unistr_t *self)
{
		return (rx_wstr_cstr(rx_unistr_to_wstr((rx_unistr_t*)self)));

}

/********************************tokenizer********************************************/

typedef struct __rx_strtok_ctx_tag 
{
		rx_char			*str;
		rx_char			*end;
		rx_char			tmp;
		rx_bool			trim;
}rx_strtok_ctx;

rx_strtok_ctx*	rx_strtok_init(const rx_char *str,  rx_bool trim)
{
		size_t len;
		rx_strtok_ctx* res;
		RX_ASSERT(str != NULL);
		len = strlen(str);
		res = (rx_strtok_ctx*)__str_alloc(sizeof(rx_strtok_ctx));
		res->str = (rx_char*)__str_alloc((len + 1) * sizeof(rx_char));
		strcpy(res->str, str);
		res->end = res->str;
		res->tmp = *res->end;
		res->trim = trim;
		return res;
}




void	rx_strtok_destroy(rx_strtok_ctx *ctx)
{
		if(ctx != NULL)
		{
				RX_ASSERT(ctx->str != NULL);
				__str_free(ctx->str);
				__str_free(ctx);
		}
}


void			rx_strtok_reset(rx_strtok_ctx *ctx)
{
		RX_ASSERT(ctx != NULL && ctx->end != NULL && ctx->str != NULL);

		*ctx->end = ctx->tmp;

		ctx->end = ctx->str;

		ctx->tmp = *ctx->str;


}




RavenAPI const rx_char*			rx_strtok(rx_strtok_ctx *ctx, rx_bool (*is_delim_f)(rx_char, const void*), const void *sep)
{
		
		rx_char *p, *e;
		RX_ASSERT(ctx != NULL && ctx->str != NULL  &&   ctx->end != NULL);

		*ctx->end = ctx->tmp;
		p = ctx->end;

		while(*p != 0)
		{
				if(ctx->trim && *p == ' ')
				{
						p++;
				}else if(is_delim_f(*p, sep))
				{
						p++;
				}else
				{
						break;		
				}
		}

		if(*p == 0)return NULL;

		e = p;

		while(*e != 0 && !is_delim_f(*e, sep))e++;
		
		if(ctx->trim){ while(*--e == L' ');    e++;}

		RX_ASSERT(e > p);

		ctx->end = e;

		ctx->tmp = *e;

		*e = 0;

		return p;



}

static rx_bool __is_sep_a(rx_char c, const void* data)
{		
		const rx_char *sep = (const rx_char*)data;
		RX_ASSERT(sep != NULL);
		while(*sep != 0 && c != *sep)sep++;

		return (*sep != 0 ?rx_true : rx_false);
}

const rx_char*	rx_strtok_str(rx_strtok_ctx *ctx, const rx_char *sep)
{
		if(sep == NULL)sep = "";
		RX_ASSERT(ctx != NULL && sep != NULL);
		return rx_strtok(ctx, __is_sep_a, (const void*)sep);


}


/**************************************wstr tokenizer************************************/




typedef struct __rx_wcstok_ctx_tag 
{
		rx_wchar			*str;
		rx_wchar			*end;
		rx_wchar			tmp;
		rx_bool				trim;
}rx_wcstok_ctx;



rx_wcstok_ctx*	rx_wcstok_init(const rx_wchar *str,  rx_bool trim)
{
		size_t len;
		rx_wcstok_ctx* res;
		RX_ASSERT(str != NULL);
		len = wcslen(str);
		res = (rx_wcstok_ctx*)__str_alloc(sizeof(rx_wcstok_ctx));
		res->str = (rx_wchar*)__str_alloc((len + 1) * sizeof(rx_wchar));
		wcscpy(res->str, str);
		res->end = res->str;
		res->tmp = *res->end;
		res->trim = trim;
		return res;
}







const rx_wchar* rx_wcstok(rx_wcstok_ctx *ctx, rx_bool (*is_delim_f)(rx_wchar, const void*), const void *sep)
{
		
		rx_wchar *p, *e;
		RX_ASSERT(ctx != NULL && ctx->str != NULL  &&   ctx->end != NULL);
		RX_ASSERT(is_delim_f != NULL);

		*ctx->end = ctx->tmp;
		p = ctx->end;

		while(*p != 0)
		{
				if(ctx->trim && *p == L' ')
				{
						p++;
				}else if(is_delim_f(*p, sep))
				{
						p++;
				}else
				{
						break;		
				}
		}

		if(*p == 0)return NULL;

		e = p;

		while(*e != 0 && !is_delim_f(*e, sep))e++;
		
		if(ctx->trim){ while(*--e == L' ');    e++;}

		RX_ASSERT(e > p);

		ctx->end = e;

		ctx->tmp = *e;

		*e = 0;

		return p;



}

static rx_bool __is_sep_w(rx_wchar c, const void* data)
{		
		const rx_wchar *sep = (const rx_wchar*)data;
		RX_ASSERT(sep != NULL);
		while(*sep != 0 && c != *sep)sep++;

		return (*sep != 0 ?rx_true : rx_false);
}

const rx_wchar*	rx_wcstok_str(rx_wcstok_ctx *ctx, const rx_wchar *sep)
{
		if(sep == NULL)sep = RX_WIDE_STR("");
		RX_ASSERT(ctx != NULL && sep != NULL);
		return rx_wcstok(ctx, __is_sep_w, (const void*)sep);


}

void	rx_wcstok_destroy(rx_wcstok_ctx *ctx)
{
		if(ctx != NULL)
		{
				RX_ASSERT(ctx->str != NULL);
				__str_free(ctx->str);
				__str_free(ctx);
		}
}



void			rx_wcstok_reset(rx_wcstok_ctx *ctx)
{
		RX_ASSERT(ctx != NULL && ctx->end != NULL && ctx->str != NULL);

		*ctx->end = ctx->tmp;
		ctx->end = ctx->str;
		ctx->tmp = *ctx->str;


}

RX_SPACE_END





